package com.ruoyi.student.service;

import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.student.domain.StudentInfo;
import com.ruoyi.student.domain.vo.ImportFailureVO;
import com.ruoyi.student.domain.vo.studentDaoShiVO;
import com.ruoyi.teacher.domain.teacher;
import com.ruoyi.teacher.service.IteacherService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;



import static com.mysql.cj.conf.PropertyKey.logger;

@Service
public class StudentTutorImportService {

    @Autowired
    private IStudentInfoService studentInfoService;

    @Autowired
    private IteacherService iteacherService;

    // 存储导入进度的线程安全Map
    private final Map<String, ImportProgress> importProgressMap = new ConcurrentHashMap<>();

    // 存储导入失败的数据
    private final Map<String, List<ImportFailureVO>> failureDataMap = new ConcurrentHashMap<>();

    /**
     * 生成导入批次号
     */
    public String generateBatchNo() {
        return "TUTOR_IMPORT_" + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8);
    }

    /**
     * 异步执行导师导入
     */
    @Async
    public Future<ImportResult> doImport(MultipartFile file, String batchNo) {
        // 初始化进度信息
        ImportProgress progress = new ImportProgress();
        progress.setBatchNo(batchNo);
        progress.setStatus("处理中");
        progress.setProgress(0);
        importProgressMap.put(batchNo, progress);

        List<ImportFailureVO> failureList = new ArrayList<>();
        List<DuplicateStudentInfo> duplicateStudents = new ArrayList<>(); // 用于记录重复学生

        try {
            // 1. 解析Excel文件
            ExcelUtil<studentDaoShiVO> excelUtil = new ExcelUtil<>(studentDaoShiVO.class);
            List<studentDaoShiVO> tutorList = excelUtil.importExcel(file.getInputStream());
            int total = tutorList.size();
            progress.setTotal(total);
            importProgressMap.put(batchNo, progress);

            if (total == 0) {
                progress.setStatus("完成");
                progress.setProgress(100);
                return new AsyncResult<>(new ImportResult(batchNo, 0, 0, "无数据需要导入"));
            }

            // 2. 预校验基础数据
            List<studentDaoShiVO> validList = tutorList.stream().filter(item -> {
                // 创建失败VO时指定原始VO和临时失败原因（后续会更新）
                ImportFailureVO failureVO = new ImportFailureVO(item, "");
                boolean isValid = true;

                if (item.getStudentId() == null || item.getStudentId().trim().isEmpty()) {
                    failureVO.setFailureReason("学号不能为空");
                    failureList.add(failureVO);
                    isValid = false;
                } else if (item.getTeacherId() == null || item.getTeacherId().trim().isEmpty()) {
                    failureVO.setFailureReason("导师工号不能为空");
                    failureList.add(failureVO);
                    isValid = false;
                }

                return isValid;
            }).collect(Collectors.toList());

            // 3. 批量查询学生是否存在
            Set<String> studentIds = validList.stream()
                    .map(studentDaoShiVO::getStudentId)
                    .collect(Collectors.toSet());
            List<StudentInfo> existStudents = studentInfoService.selectStudentInfoByStudentIds(new ArrayList<>(studentIds));
            Set<String> existStudentIds = existStudents.stream()
                    .map(StudentInfo::getStudentId)
                    .collect(Collectors.toSet());

            // 4. 批量查询导师是否存在
            Set<String> teacherIds = validList.stream()
                    .map(studentDaoShiVO::getTeacherId)
                    .collect(Collectors.toSet());
            List<teacher> existTeachers = iteacherService.selectTeacherByTeacherIds(new ArrayList<>(teacherIds));
            Set<String> existTeacherIds = existTeachers.stream()
                    .map(teacher::getTeacherCode)
                    .collect(Collectors.toSet());

            // 5. 处理数据并绑定导师
            int successCount = 0;
            int batchSize = 50; // 每50条一批处理

            for (int i = 0; i < validList.size(); i++) {
                studentDaoShiVO item = validList.get(i);
                // 使用新的构造函数创建失败VO
                ImportFailureVO failureVO = new ImportFailureVO(item, "");
                String currentStudentId = item.getStudentId().trim();
                String currentTeacherId = item.getTeacherId().trim();

                // 校验学生是否存在
                if (!existStudentIds.contains(currentStudentId)) {
                    failureVO.setFailureReason("学号不存在");
                    failureList.add(failureVO);
                    updateProgress(progress, i + 1 + failureList.size(), total, successCount, failureList.size());
                    continue;
                }

                // 校验导师是否存在
                if (!existTeacherIds.contains(currentTeacherId)) {
                    failureVO.setFailureReason("导师工号不存在");
                    failureList.add(failureVO);
                    updateProgress(progress, i + 1 + failureList.size(), total, successCount, failureList.size());
                    continue;
                }
                //检验上传的学生名字和数据库中的名字是否一致如果不一致无法导入
                StudentInfo dbStudent = studentInfoService.selectStudentInfoByStudentId(currentStudentId);
                if(!item.getStudentName().equals(dbStudent.getStudentName())){
                    failureVO.setFailureReason("学生姓名不一致");
                    failureList.add(failureVO);
                    updateProgress(progress, i + 1 + failureList.size(), total, successCount, failureList.size());
                    continue;
                }

                // 检查是否为重复导入（学生已经有导师）
                if (dbStudent.getStudentDsbh() != null && !dbStudent.getStudentDsbh().isEmpty()) {
                    // 如果学生已经有导师，记录为重复学生（无论新旧导师是否相同）
                    String oldTeacherName = dbStudent.getStudentDs() != null ? dbStudent.getStudentDs() : "未知";
                    String newTeacherName = item.getTeacherName();
                    String oldTeacherId = dbStudent.getStudentDsbh();

                    String oldTeacherInfo = oldTeacherName + "(" + oldTeacherId + ")";
                    String newTeacherInfo = newTeacherName + "(" + currentTeacherId + ")";

                    // 总是记录已有导师的学生
                    DuplicateStudentInfo duplicateInfo = new DuplicateStudentInfo(
                            currentStudentId,
                            item.getStudentName(),
                            oldTeacherInfo,
                            newTeacherInfo
                    );
                    duplicateStudents.add(duplicateInfo);
                }


                // 执行绑定（这里可以根据之前的修改改为update方法）
                String uuid = dbStudent.getId();
                StudentInfo studentInfo = new StudentInfo();
                studentInfo.setId(uuid);
                studentInfo.setStudentId(currentStudentId);
                studentInfo.setStudentDsbh(item.getTeacherId());
                studentInfo.setStudentDs(item.getTeacherName());
                int result = studentInfoService.updateStudentInfo(studentInfo);
                if (result > 0) {
                    successCount++;
                } else {
                    failureVO.setFailureReason("绑定失败，数据库更新异常");
                    failureList.add(failureVO);
                }

                // 更新进度
                updateProgress(progress, i + 1 + failureList.size(), total, successCount, failureList.size());

                // 每处理一定数量休眠短暂时间，避免数据库压力过大
                if ((i + 1) % batchSize == 0) {
                    Thread.sleep(100);
                }
            }

            // 6. 保存失败数据
            if (!failureList.isEmpty()) {
                failureDataMap.put(batchNo, failureList);
                // 24小时后清理失败数据
                scheduleFailureDataCleanup(batchNo);
            }

            // 7. 完成处理
            progress.setStatus("完成");
            progress.setProgress(100);
            progress.setSuccessCount(successCount);
            progress.setFailCount(failureList.size());
            progress.setDuplicateStudents(duplicateStudents); // 设置重复学生信息
            importProgressMap.put(batchNo, progress);

            return new AsyncResult<>(new ImportResult(batchNo, successCount, failureList.size(), "导入完成"));

        } catch (IOException e) {
            progress.setStatus("失败");
            progress.setErrorMsg("文件解析失败：" + e.getMessage());
            importProgressMap.put(batchNo, progress);
            return new AsyncResult<>(new ImportResult(batchNo, 0, 0, "文件解析失败：" + e.getMessage()));
        } catch (InterruptedException e) {
            progress.setStatus("失败");
            progress.setErrorMsg("导入被中断：" + e.getMessage());
            importProgressMap.put(batchNo, progress);
            Thread.currentThread().interrupt();
            return new AsyncResult<>(new ImportResult(batchNo, 0, 0, "导入被中断：" + e.getMessage()));
        } catch (Exception e) {
            progress.setStatus("失败");
            progress.setErrorMsg("导入异常：" + e.getMessage());
            importProgressMap.put(batchNo, progress);
            return new AsyncResult<>(new ImportResult(batchNo, 0, 0, "导入异常：" + e.getMessage()));
        }
    }



    /**
     * 查询导入进度
     */
    public ImportProgress getImportProgress(String batchNo) {
        return importProgressMap.getOrDefault(batchNo, new ImportProgress());
    }

    /**
     * 下载失败数据
     */
    public void downloadFailureData(String batchNo, HttpServletResponse response) throws IOException {
        List<ImportFailureVO> failureList = failureDataMap.get(batchNo);
        if (failureList == null || failureList.isEmpty()) {
            throw new IOException("该批次没有失败数据或数据已过期");
        }

        ExcelUtil<ImportFailureVO> util = new ExcelUtil<>(ImportFailureVO.class);
        util.exportExcel(response, failureList, "导师导入失败数据_" + batchNo);
    }

    /**
     * 下载导入模板
     */
    public void downloadTemplate(HttpServletResponse response) throws IOException {
        ExcelUtil<studentDaoShiVO> util = new ExcelUtil<>(studentDaoShiVO.class);
        // 指定只显示这些字段对应的属性名
        util.showColumn("studentId", "studentName", "teacherId", "teacherName");

        List<studentDaoShiVO> templateData = new ArrayList<>();

        // 创建一个用于存储表头的 VO 对象
        studentDaoShiVO headerVO = new studentDaoShiVO();
        headerVO.setStudentId("学号"); // 设置表头文字
        headerVO.setStudentName("姓名");
        headerVO.setTeacherId("导师工号");
        headerVO.setTeacherName("导师姓名");
        templateData.add(headerVO); // 将表头对象添加到数据列表中

        // 导出 Excel，现在第一行将是表头
        util.importTemplateExcel(response, String.valueOf(templateData), "学生导师指定导入模板");
    }



    /**
     * 更新进度信息
     */
    private void updateProgress(ImportProgress progress, int current, int total, int successCount, int failCount) {
        progress.setProgress((int) ((current * 1.0 / total) * 100));
        progress.setSuccessCount(successCount);
        progress.setFailCount(failCount);
        importProgressMap.put(progress.getBatchNo(), progress);
    }

    /**
     * 定时清理失败数据
     */
    private void scheduleFailureDataCleanup(String batchNo) {
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                failureDataMap.remove(batchNo);
                importProgressMap.remove(batchNo);
            }
        }, 86400000); // 24小时后清理
    }

    /**
     * 导入进度内部类
     */
    public static class ImportProgress {
        private String batchNo;
        private String status; // 处理中/完成/失败
        private int progress; // 0-100
        private int total; // 总条数
        private int successCount; // 成功条数
        private int failCount; // 失败条数
        private String errorMsg; // 错误信息
        private List<DuplicateStudentInfo> duplicateStudents = new ArrayList<>(); // 重复学生信息

        // Getter和Setter
        public String getBatchNo() { return batchNo; }
        public void setBatchNo(String batchNo) { this.batchNo = batchNo; }
        public String getStatus() { return status; }
        public void setStatus(String status) { this.status = status; }
        public int getProgress() { return progress; }
        public void setProgress(int progress) { this.progress = progress; }
        public int getTotal() { return total; }
        public void setTotal(int total) { this.total = total; }
        public int getSuccessCount() { return successCount; }
        public void setSuccessCount(int successCount) { this.successCount = successCount; }
        public int getFailCount() { return failCount; }
        public void setFailCount(int failCount) { this.failCount = failCount; }
        public String getErrorMsg() { return errorMsg; }
        public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; }
        public List<DuplicateStudentInfo> getDuplicateStudents() { return duplicateStudents; }
        public void setDuplicateStudents(List<DuplicateStudentInfo> duplicateStudents) { this.duplicateStudents = duplicateStudents; }

        @Override
        public String toString() {
            return "ImportProgress{" +
                    "batchNo='" + batchNo + '\'' +
                    ", status='" + status + '\'' +
                    ", progress=" + progress +
                    ", total=" + total +
                    ", successCount=" + successCount +
                    ", failCount=" + failCount +
                    ", errorMsg='" + errorMsg + '\'' +
                    ", duplicateStudents=" + duplicateStudents +
                    '}';
        }
    }

    /**
     * 重复学生信息类
     */
    public static class DuplicateStudentInfo {
        private String studentId;    // 学号
        private String studentName;  // 学生姓名
        private String oldTeacher;   // 原导师
        private String newTeacher;   // 新导师

        public DuplicateStudentInfo() {}

        public DuplicateStudentInfo(String studentId, String studentName, String oldTeacher, String newTeacher) {
            this.studentId = studentId;
            this.studentName = studentName;
            this.oldTeacher = oldTeacher;
            this.newTeacher = newTeacher;
        }

        // Getter和Setter
        public String getStudentId() { return studentId; }
        public void setStudentId(String studentId) { this.studentId = studentId; }
        public String getStudentName() { return studentName; }
        public void setStudentName(String studentName) { this.studentName = studentName; }
        public String getOldTeacher() { return oldTeacher; }
        public void setOldTeacher(String oldTeacher) { this.oldTeacher = oldTeacher; }
        public String getNewTeacher() { return newTeacher; }
        public void setNewTeacher(String newTeacher) { this.newTeacher = newTeacher; }
    }



    /**
     * 导入结果内部类
     */
    public static class ImportResult {
        private String batchNo;
        private int successCount;
        private int failCount;
        private String msg;

        public ImportResult(String batchNo, int successCount, int failCount, String msg) {
            this.batchNo = batchNo;
            this.successCount = successCount;
            this.failCount = failCount;
            this.msg = msg;
        }

        // Getter和Setter
        public String getBatchNo() { return batchNo; }
        public void setBatchNo(String batchNo) { this.batchNo = batchNo; }
        public int getSuccessCount() { return successCount; }
        public void setSuccessCount(int successCount) { this.successCount = successCount; }
        public int getFailCount() { return failCount; }
        public void setFailCount(int failCount) { this.failCount = failCount; }
        public String getMsg() { return msg; }
        public void setMsg(String msg) { this.msg = msg; }
    }
}
